#if !defined(MAIN_H)
#define MAIN_H

#include <vector>
#include <ext/hash_map>
#include <deque>
#include <numeric>
#include <algorithm>
#include <list>
#include <string>


#include <progress_indicator.h>
#include <print_error.h>
#include <tab_delimited_str.h>
#include <stlhelper.h>
#include <index_string.h>


//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

//	t_micro_block

//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
enum eORIENTATION {eFORWARDS, eBACKWARDS, eUNDETERMINED};
typedef std::deque<std::deque<unsigned> > t_deq_deq_u;
const unsigned UNKNOWN = std::numeric_limits<unsigned>::max();
struct t_micro_block
{
    std::deque<unsigned>	gene_positions;
	std::vector<unsigned>	ortholog_ids;
	unsigned				ortho_beg;
	unsigned				ortho_end;
	unsigned				ortholog_id_beg;
	unsigned				ortholog_id_end;
    eORIENTATION        	orientation;
	const t_deq_deq_u&		rel_ortholog_sets;


							t_micro_block(unsigned				ortholog_id,
										  const t_deq_deq_u&	rel_ortholog_sets_,
										  unsigned				gene_pos,
										  eORIENTATION			orientation_):	
											ortho_beg(UNKNOWN),
											ortho_end(UNKNOWN),
											ortholog_id_beg(ortholog_id),
											ortholog_id_end(ortholog_id),
											orientation(orientation_),
											rel_ortholog_sets(rel_ortholog_sets_)
											{
												gene_positions.push_back(gene_pos);
												ortholog_ids.push_back(ortholog_id);
											}
	unsigned				size() const {return gene_positions.size();	}
	void					dump (std::ostream&			outstrm, 
								  std::deque<unsigned>&	rel_gene_pos_to_gene_pos) const;
	void					dump (std::ostream& outstrm) const;
	void					add_ortho_gene_pos(unsigned rel_gene_pos1, 
											   unsigned rel_gene_pos2, 
											   unsigned ortholog_id);
	std::string 					orientation_name() const;
	bool					is_flipped_contiguous(const t_micro_block& other) const;
};

inline std::ostream& operator << (std::ostream& os, const t_micro_block& block)
{
	block.dump(os);
	return os;
}

typedef std::list<t_micro_block> t_micro_blocks;
typedef std::deque<t_micro_blocks> t_micro_blocks_by_chromosome;



//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

//	t_macro_block

//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
struct t_macro_block
{
						t_macro_block(t_micro_blocks& 			micro_blocks, 
									  t_micro_blocks::iterator	iter) : 
								rel_ortholog_sets(iter->rel_ortholog_sets),
								ortho_beg(iter->ortho_beg), 
								ortho_end(iter->ortho_end), 
								ortholog_id_beg(iter->ortholog_id_beg),
								ortholog_id_end(iter->ortholog_id_end),
								m_size(iter->size())
								{
									blocks.splice(blocks.end(), micro_blocks, iter);
								}

	bool 				operator && (const t_macro_block& other);
	void				prepend(t_macro_block& other);
	unsigned			size()	const { return m_size;}
	void				push_back(t_micro_blocks& micro_blocks, t_micro_blocks::iterator iter);
	bool				is_flipped_contiguous(const t_micro_block& block) const;

	t_micro_blocks		blocks;
	const t_deq_deq_u&	rel_ortholog_sets;
	unsigned 			ortho_beg;
	unsigned 			ortho_end;
	unsigned			ortholog_id_beg;
	unsigned			ortholog_id_end;
	unsigned 			m_size;
};

inline bool t_macro_block::is_flipped_contiguous(const t_micro_block& block) const
{
	assert (blocks.size());
	return block.is_flipped_contiguous(blocks.back());
}
#endif
